package cn.yshujia.service.impl;

import cn.yshujia.domain.dto.PageDTO;
import cn.yshujia.domain.entity.Article;
import cn.yshujia.domain.vo.ArchiveVO;
import cn.yshujia.domain.vo.ArticleVO;
import cn.yshujia.domain.vo.PageVO;
import cn.yshujia.mapper.ArticleMapper;
import cn.yshujia.repository.ArticleRepository;
import cn.yshujia.utils.IDUtils;
import cn.yshujia.utils.MinioUtils;
import cn.yshujia.utils.PageUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * @author YShuJia
 * @create 2024/4/23
 * @description 服务层
 */

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IService<Article> {
	
	@Resource
	ArticleMapper mapper;
	
	@Resource
	ArticleRepository repository;
	
	@Resource
	BCryptPasswordEncoder passwordEncoder;
	
	public ArticleVO selectArticle(Long id) {
		return repository.get(id);
	}
	
	public PageVO<ArticleVO> pageByLabelId(PageDTO dto) {
		return repository.pageByLabelId(dto);
	}
	
	public List<ArchiveVO> selectArchiveList() {
		return repository.selectArchiveList();
	}
	
	public List<ArticleVO> selectRecommendList() {
		return repository.selectRecommendList();
	}
	
	public List<ArticleVO> selectDeployList() {
		return repository.selectDeployList();
	}
	
	public PageVO<ArticleVO> adminPage(PageDTO dto) {
		QueryWrapper<Article> wrapper = PageUtils.createArticleWrapper(dto);
		wrapper.orderByDesc("create_time");
		
		IPage<Article> page = mapper.selectPage(new Page<>(dto.getCurrent(), dto.getSize()), wrapper);
		
		// 创建VO集合
		if (!ObjectUtils.isEmpty(page) && !ObjectUtils.isEmpty(page.getRecords())) {
			return PageUtils.getPage(dto, repository.createVOList(page.getRecords()), page.getTotal());
		}
		return new PageVO<>();
	}
	
	@Transactional (rollbackFor = {Exception.class})
	public Boolean insert(Article dto, List<String> urls) {
		dto.setId(IDUtils.getId());
		if (null != dto.getPassword() && !dto.getPassword().isEmpty()) {
			dto.setPassword(passwordEncoder.encode(dto.getPassword()));
		}
		Set<String> newUrls = getArticleUrls(dto.getContent());
		
		try {
			int n = mapper.insert(dto);
			if (n > 0) {
				// 去掉域名，去除新上传后未使用的图片
				if (!ObjectUtils.isEmpty(urls)) {
					// 在 urls 中 移除 newUrls 中有的元素
					newUrls.forEach(urls::remove);
				}
				MinioUtils.delete(urls);
				repository.del();
			}
			return n > 0;
		} catch (Exception e) {
			MinioUtils.delete(urls);
			return false;
		}
	}
	
	@Transactional (rollbackFor = {Exception.class})
	public Boolean update(Article dto, List<String> urls) {
		// 获取旧文章中的图片地址
		ArticleVO vo = repository.get(dto.getId());
		Set<String> oldUrls = getArticleUrls(vo.getContent());
		
		Set<String> newUrls = getArticleUrls(dto.getContent());
		// 在 oldUrls中 移除 newUrls 中有的元素
		newUrls.forEach(oldUrls::remove);
		
		if (null != dto.getPassword() && !dto.getPassword().isEmpty()) {
			dto.setPassword(passwordEncoder.encode(dto.getPassword()));
		}
		try {
			int n = mapper.updateById(dto);
			if (n > 0) {
				repository.del();
				// 去掉域名，去除新上传后未使用的图片
				if (!ObjectUtils.isEmpty(urls)) {
					// 在 urls 中 移除 newUrls 中有的元素
					newUrls.forEach(urls::remove);
				}
				MinioUtils.delete(urls);
				MinioUtils.delete(oldUrls);
			}
			return n > 0;
		} catch (Exception e) {
			MinioUtils.delete(urls);
			return false;
		}
	}
	
	private Set<String> getArticleUrls(String content) {
		Pattern pattern = Pattern.compile("src='(.*?)'");
		Matcher matcher = pattern.matcher(content);
		// 用于存储 src 内容的列表
		Set<String> set = new HashSet<>();
		// 查找所有匹配项并提取 src 值
		while (matcher.find()) {
			// 将提取到的 src 添加到列表中
			set.add(matcher.group(1));
		}
		return set;
	}
}
